import { useState, useReducer } from 'react'
import Schema, {
  RuleItem, // 提供了一套校验规则
  ValidateError // 校验错误信息格式
} from 'async-validator'
import mapValues from 'lodash-es/mapValues'
import each from 'lodash-es/each'

export type CustomRuleFunc = ({ getFieldValue }) => RuleItem // 自定义校验方法
export type CustomRule = RuleItem | CustomRuleFunc // 自定义校验规则
export interface FieldDetail {
  name: string // 字段名
  value: string // 字段值
  rules: CustomRule[] // 校验规则
  isValid: boolean // 校验是否通过
  errors: ValidateError[] // 校验错误信息
}
export interface FieldsState {
  [key: string]: FieldDetail // 每一项对应一个
}

export interface ValidateErrorType extends Error {
  errors: ValidateError[]
  fields: Record<string, ValidateError[]>
}
export interface FormState {
  isValid: boolean // 表单是否校验通过
  isSubmitting: boolean // 是否正在提交
  errors: Record<string, ValidateError[]> // 表单错误信息
}
// action类型
export interface FieldsAction {
  type: 'addField' | 'updateValue' | 'updateValidateResult'
  name: string
  value: any
}

function fieldsReducer(state: FieldsState, action: FieldsAction) {
  switch (action.type) {
    case 'addField': // 添加字段
      return {
        ...state,
        [action.name]: { ...action.value }
      }
    case 'updateValue': // 更新字段值
      return {
        ...state,
        [action.name]: { ...state[action.name], value: action.value }
      }
    case 'updateValidateResult': // 更新校验结果
      const { isValid, errors } = action.value
      return {
        ...state,
        [action.name]: { ...state[action.name], isValid, errors }
      }
    default:
      return state
  }
}

function useStore(initialValues?: Record<string, any>) {
  // 表单状态
  const [form, setForm] = useState<FormState>({
    isValid: false, // 表单是否校验通过
    isSubmitting: false, // 是否正在提交
    errors: {} // 表单错误信息
  })

  // 每个字段(name)对应一个 FieldDetail
  const [fields, dispatch] = useReducer(
    fieldsReducer, // reducer函数
    {} // 初始状态
  )

  // 根据传入的key获取对应的value
  const getFieldValue = (key: string) => fields[key] && fields[key].value
  // 获取所有表单字段的值
  const getFieldsValue = () => {
    return mapValues(fields, (item) => item.value)
  }
  // 设置字段的值
  const setFieldValue = (name: string, value: any) => {
    if (fields[name]) {
      dispatch({ type: 'updateValue', name, value })
    }
  }
  // 定义一个重置字段的方法
  const resetFields = () => {
    // const initValueKeys = initialValues && Object.keys(initialValues)
    // const fieldsKey = Object.keys(fields)
    // fieldsKey.forEach((name) => {
    //   if (initValueKeys && initValueKeys.includes(name)) {
    //     dispatch({ type: 'updateValue', name, value: initialValues[name] })
    //   } else {
    //     dispatch({ type: 'updateValue', name, value: '' })
    //   }
    //   dispatch({ type: 'updateValidateResult', name, value: { isValid: true, errors: [] } })
    // })
    if (initialValues) {
      each(initialValues, (value, name) => {
        if (fields[name]) {
          dispatch({ type: 'updateValue', name, value })
        }
      })
    }
  }
  // 判断校验是否有方法
  const transfromRules = (rules: CustomRule[]) => {
    return rules.map((rule) => {
      // 如果是函数，
      if (typeof rule === 'function') {
        const calledRule = rule({ getFieldValue }) // 传入获取字段值的方法
        return calledRule // 返回调用结果
      } else return rule // 不是函数，则直接返回rule
    })
  }
  // 验证单个字段
  const validateField = async (name: string) => {
    const { value, rules } = fields[name] // 获取字段值和规则
    const afterRules = transfromRules(rules) // 转换规则
    // 创建验证器实例
    const validator = new Schema({
      [name]: afterRules
    })
    let isValid = true
    let errors: ValidateError[] = [] // 错误信息
    try {
      await validator.validate({
        [name]: value
      }) // 验证字段值
    } catch (e) {
      isValid = false // 设置字段无效
      const err = e as any
      // console.warn('errors', err.errors)
      console.warn('fields', err.fields)
      errors = err.errors // 获取错误信息
    } finally {
      // console.log('是否通过 ', isValid) // 是否通过
      dispatch({ type: 'updateValidateResult', name, value: { isValid, errors } }) // 更新验证结果
    }
  }
  // 验证所有字段
  const validateAllFields = async () => {
    let isValid = true
    let errors: Record<string, ValidateError[]> = {} // 错误信息
    const valueMap = mapValues(fields, (item) => item.value)
    const descriptor = mapValues(fields, (item) => transfromRules(item.rules))
    const validator = new Schema(descriptor)
    setForm({ ...form, isSubmitting: true }) // 设置表单正在提交
    console.log('fields', fields)
    try {
      await validator.validate(valueMap) // 验证表单字段
    } catch (e) {
      isValid = false // 如果验证失败，设置表单无效
      const err = e as ValidateErrorType
      console.log('err', err.fields)
      errors = err.fields // 错误信息存储
      each(fields, (value, name) => {
        if (errors[name]) {
          // 如果有错误信息
          const itemErrors = errors[name]
          dispatch({ type: 'updateValidateResult', name, value: { isValid: false, errors: itemErrors } })
        } else if (value.rules.length > 0 && !errors[name]) {
          // 如果没有错误信息，但是有规则
          dispatch({ type: 'updateValidateResult', name, value: { isValid: true, errors: [] } })
        }
      })
    } finally {
      setForm({ ...form, isSubmitting: false, isValid, errors }) // 设置表单状态
      return {
        isValid,
        errors,
        values: valueMap
      }
    }
  }
  return {
    fields, // 每个字段对应状态
    form, // 整个表单状态
    dispatch,
    getFieldValue, // 获取字段值
    validateField, // 验证单个字段
    validateAllFields, // 验证所有字段
    getFieldsValue, // 获取所有字段值
    setFieldValue, // 设置字段值
    resetFields // 重置字段值
  }
}
export default useStore
